#include "SceneGraph.h"



CSceneGraph::CSceneGraph(CD3D9Engine* ptrEngine)
{
	_ptrEngine = ptrEngine;
	_nodes = new std::list<CSceneNode*>;


	_addedNodeLastFrame = true;
	_sortSceneNodes = true;
	_debugNodeBB = false;


	SetRect(&_renderArea, 0, 0, 0, 0);
}


CSceneGraph::~CSceneGraph()
{
	SAFE_DELETE(_nodes);
}


void CSceneGraph::ClearScene()
{
	if(_nodes != NULL)
	{
		_nodes->clear();
	}
}


void CSceneGraph::ClearSceneAndDelete()
{
	if(_nodes != NULL)
	{
		std::list<CSceneNode*>::iterator iter;

		for(iter = _nodes->begin();
			iter != _nodes->end();
			++iter)
		{
			CSceneNode* node = (CSceneNode*)(*iter);
			node->Release();
			SAFE_DELETE(node);
		}

		_nodes->clear();
	}
}


CSceneNode* CSceneGraph::AddNodeToScene(char* nodeName, CSceneNode *node)
{
	if(node != NULL)
	{
		node->_nodeDisplayName = nodeName;
		node->_nodeHash = 11;
		node->_inSceneGraph = true;

		_nodes->push_back(node);
		

		_addedNodeLastFrame = true;
	}

	return node;
}


CSceneNode* CSceneGraph::RemoveNodeFromScene(CSceneNode *node)
{
	if(node != NULL)
	{
		node->_inSceneGraph = false;
		node->_nodeDisplayName = NULL;
		node->_nodeHash = 0;

		_nodes->remove(node);


		_addedNodeLastFrame = true;
	}

	return node;
}


int CSceneGraph::GetSceneNodeCount()
{
	if(_nodes != NULL)
	{
		return (int)_nodes->size();
	}

	return 0;
}


CSceneNode* CSceneGraph::GetNodeByName(char* name)
{
	for(std::list<CSceneNode*>::iterator iter = _nodes->begin(); iter != _nodes->end(); ++iter)
	{
		if(strcmp(name, ((CSceneNode*)*iter)->GetNodeName()) == 0)
			return ((CSceneNode*)*iter);
	}

	return NULL;
}


CSceneNode* CSceneGraph::GetNodeByID(int id)
{
	if(id >= 0 &&
		id < (int)this->_nodes->size())
	{
		std::list<CSceneNode*>::iterator iter = _nodes->begin();
		std::advance(iter, id);											// PERFORMANCE HIT, FUCK, DONT USE TOO OFTEN
		return (CSceneNode*)*iter;
	}

	return NULL;
}



void CSceneGraph::RenderScene()
{
	if(_ptrEngine == NULL)
		return;

	//	1:		sort scene
	if(_sortSceneNodes)
	{
		if(_addedNodeLastFrame)
		{
			_nodes->sort();
			_addedNodeLastFrame = false;
		}

	}


	//	2:		transform nodes & render
	std::list<CSceneNode*>::iterator iter;

	for(iter = _nodes->begin();
		iter != _nodes->end();
		++iter)
	{
		CSceneNode* node = (*iter);
		NODE_TYPE type = node->GetType();
		D3DXMATRIX transform;

		transform = this->CalculateNodeTransformation(node, true);

		node->WorldTransformation = transform;

		if(type == NODE_POSITION_REF)
		{
			CScenePosRef* ref = dynamic_cast<CScenePosRef*>(node);
			RenderNode(ref->GetRefObject(), node);
		}
		else
		{
			RenderNode(node, NULL);
		}
	}
}


void CSceneGraph::RenderNode(CSceneNode* node, CSceneNode* ref)
{
	if(node->IsRenderable())
	{
		IRenderable* renderIFace = dynamic_cast<IRenderable*>(node);

		if(renderIFace->GetRender() != false)
		{
			if(ref != NULL)
			{
			
				_ptrEngine->Render(renderIFace, &(ref->WorldTransformation));
			}
			else
			{
				_ptrEngine->Render(renderIFace, NULL);
			}

		}
	}
}


void CSceneGraph::UpdateScene(float delta)
{
	std::list<CSceneNode*>::iterator iter;

	for(iter = _nodes->begin();
		iter != _nodes->end();
		++iter)
	{
		CSceneNode* node = (*iter);
	
		if(node->DynamicMotion)
			node->Position += node->Acceleration * delta;
		else
			node->Position += node->Acceleration;

		node->Update(delta);

		node->Acceleration = D3DXVECTOR3(0,0,0);
	}
}


D3DXMATRIX CSceneGraph::CalculateNodeTransformation(CSceneNode *node, bool traverse)
{
	D3DXMATRIX ret;
	D3DXMatrixIdentity(&ret);

	switch(node->GetEntityType())
	{
	case ENTITY_SPRITE:
		
		D3DXMatrixTransformation2D(&ret, 
			&D3DXVECTOR2(node->ScaleCenter.x, node->ScaleCenter.y),
			0.0f,
			&D3DXVECTOR2(node->Scale.x, node->Scale.y),
			&D3DXVECTOR2(node->RotCenter.x, node->RotCenter.y),
			D3DXToRadian(node->Rotation),
			&D3DXVECTOR2(node->Position.x, node->Position.y));

		break;
	case ENTITY_TEXT:

		D3DXMatrixTranslation(&ret, node->Position.x, node->Position.y, node->Position.z);

		break;
	}


	if(traverse)
	{
		if(node->GetParent() != NULL)
		{
			D3DXMATRIX parent;

			parent = CalculateNodeTransformation(node->GetParent(), traverse);

			ret = ret * parent;
		}
	}

	return ret;
}
